什么是 2FA
多因素身份验证(MFA)是一种验证用户身份的方式,比传统的用户名与密码组合更加安全。MFA 通常包含一个密码,但同时也包含一个或两个其他身份验证因素。双因素身份验证 (2FA)是 MFA 的一种。
接口
1. 启用 2FA
-
接口:
POST /mfa/setup
-
描述:该接口用于启动启用 2FA 的过程。它会生成一个 TOTP 密钥,并返回一个二维码 URL,用户可以通过扫描此二维码在身份验证应用(如 Google Authenticator)中配置 2FA。
-
请求:
{ "user_id": "123" }
-
响应:
{
"secret": "JBSWY3DPEHPK3PXP",
"qr_code_url": "otpauth://totp/yourapp:username?secret=JBSWY3DPEHPK3PXP&issuer=yourapp"
}
2. 验证 2FA 配置
-
接口:
POST /mfa/verify
-
描述:用户输入由身份验证应用生成的一次性密码(OTP),用来验证 2FA 配置是否成功。
-
请求:
{ "user_id": "123", "code": "123456" }
-
响应:返回结果指示验证码是否正确以及 2FA 是否成功验证。
3. 登录时进行 2FA 验证
-
接口:
POST /mfa/login/verify
-
描述:用户登录成功后,提交用户名和密码后,需要调用此接口进行第二步验证(即 OTP 验证)。
-
请求:
{
"user_id": "123",
"password": "user_password",
"code": "123456"
}
- **响应**:如果 OTP 验证通过,系统将返回 JWT 令牌或会话信息,允许用户访问系统。
`{ "token": "JWT_token_value" }`
### 4. **禁用 2FA(停用)**
- **接口**:`POST /mfa/disable`
- **描述**:此接口用于在验证身份后禁用用户的 2FA。
- **请求**:
`{ "user_id": "123", "code": "123456" }`
- **响应**:返回成功消息,指示 2FA 已禁用。
### 5. **检查 2FA 状态**
- **接口**:`GET /mfa/status`
- **描述**:此接口用于检查用户是否已经启用 2FA。它帮助系统决定是否提示用户设置 2FA。
- **响应**:
`{ "enabled": true }`
---
### 其他注意事项:
- **密码验证**:可能需要额外的接口,用于验证密码,尤其是在修改 2FA 设置或禁用 2FA 时。
- **错误处理**:应该为错误情况提供适当的错误消息和响应代码,例如验证码错误、验证码过期或网络故障等。
## 多应用验证
在 TOTP (时间同步的一次性密码) 中,二维码链接的 URL(例如 `otpauth://totp/yourapp:username?secret=JBSWY3DPEHPK3PXP&issuer=yourapp`)可以支持多个应用验证,方法是通过适当的配置生成相同的共享密钥,并将其提供给不同的应用。TOTP 标准采用了 `otpauth://` 协议,它包含了 `secret`(密钥)和 `issuer`(颁发者)等信息。这些信息可以被用于多个不同的应用。关键是 **密钥**(`secret`)相同,无论哪个应用都可以根据这个密钥和时间戳计算出相同的一次性密码。
## OTP 验证原理
TOTP(基于时间的一次性密码)验证的核心是基于一个共享密钥(`secret`)和时间戳。TOTP 使用 HMAC(哈希消息认证码)和时间窗口来生成一次性密码。
### 验证成功的流程:
1. **共享密钥**:当用户设置 2FA 时,系统会生成一个共享密钥(`secret`),并通过二维码或其他方式将其传递给用户的身份验证应用(如 Google Authenticator)。这个密钥是两端(服务器和客户端)共享的,只有用户的身份验证应用和服务器能知道。
2. **生成 OTP**:
- 用户的身份验证应用(如 Google Authenticator)根据当前的时间和共享密钥计算一个基于时间的哈希值。TOTP 的计算方法如下:
`OTP = HMAC-SHA1(secret, time)`
- 这里的 `time` 是基于当前 UTC 时间的一个时间段(通常是 30 秒为一个时间窗口)。通过时间戳来确保每 30 秒生成一个新的 OTP。
3. **用户输入 OTP**:用户在登录时,输入应用生成的 OTP,系统将使用相同的 `secret` 和当前时间计算出相应的 OTP,验证是否与用户输入的 OTP 相匹配。
4. **校验 OTP**:
- 服务器使用与用户身份验证应用相同的密钥(`secret`)和当前时间窗口(通常是 30 秒)来计算一次性密码(OTP)。
- 如果用户输入的 OTP 与计算出来的 OTP 相匹配(通常还会允许一定的时间误差,如几秒钟内的匹配),则验证成功。
### 为什么能验证成功?
- **时间同步**:用户的身份验证应用和服务器都根据相同的共享密钥和时间戳计算 OTP。由于两者在同一时间使用相同的密钥和时间窗口生成 OTP,所以两者能够生成相同的验证码。
- **哈希算法**:TOTP 使用的 HMAC-SHA1 算法是一个加密算法,它保证了在相同输入(时间和共享密钥)下,生成的 OTP 是一致的,因此可以用来验证身份。
**总结**:
- 2FA 验证成功的原理是基于共享密钥和时间戳,确保双方生成的 OTP 是一致的。
- 即使是不同的应用,只要使用相同的 `secret` 和时间窗口,生成的 OTP 也是相同的,因此可以成功验证用户的身份。
## 备用验证码
备用验证码是一种在用户无法使用主要的 2FA 设备(如手机应用)时提供的应急方案。下面介绍一下备用验证码的生成方式及最佳实践:
### 生成方式
- **随机生成**
使用加密安全的随机数生成器(例如 Go 语言中的 `crypto/rand` 包)生成一组不可预测的验证码。
- 可生成固定长度的数字串或字母数字混合串(例如 8–10 个字符),保证足够的熵,防止暴力破解。
- **单次使用**
每个备用验证码只能使用一次。生成后需标记为未使用,使用后立即作废。
- **数量设置**
通常在设置 2FA 时生成 8-10 个备用验证码,供用户在紧急情况下使用。
### 最佳实践
- **安全存储**
将备用验证码在存储前进行哈希处理(类似密码的处理方式),这样即便数据库泄露,明文验证码也不会直接暴露。
- 推荐使用 bcrypt、Argon2 等安全的哈希算法。
- **一次性展示**
在生成备用验证码后,仅在一次性页面或下载中展示给用户,之后不再显示。
- 用户需要将其妥善保存,如打印或存入密码管理器中。
- **使用后失效**
一旦用户使用了某个备用验证码,应立即将其标记为“已使用”,防止重复使用。
- **重新生成机制**
当备用验证码全部用尽或者用户需要重新生成时,允许用户触发备用验证码重置操作。重置后应使旧验证码全部失效,并生成一组新的备用验证码。
- **用户提示**
清晰告知用户备用验证码的重要性,并提醒其在安全环境下保存,避免随意存放或泄露。